<?php

namespace App\Library\Wechat;

use App\Helpers\LogHelper;
use App\Library\BaseApi;
use WeChatPay\Builder;
use WeChatPay\BuilderChainable;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;

/**
 *
 */
class BaseWechatApi extends BaseApi
{
    protected static string $domain;
    protected static string $appId;
    protected static string $appSecret;
    protected static string $appPayId;
    protected static string $mchId;
    protected static string $serial;
    protected static string $mchSecretKey;

    protected static string $certPem;
    protected static string $apiClientKeyPem;
    protected static string $apiClientCertPem;

    protected static string $notifyPath;

    // 支付相关接口地址
    const PAY_ORDER_APP         = 'v3/pay/transactions/app';                          // app下单获取支付信息
    const PAY_ORDER_CANCEL      = 'v3/pay/transactions/out-trade-no/%s/close';        // 关闭订单API
    const PAY_TRANSACTION_QUERY = 'v3/pay/transactions/out-trade-no/%s';              // 查询订单


    // 用户相关接口地址
    const GET_APPLET_ACCESS_TOKEN = '/cgi-bin/token';                                 // 获取access_token

    const GET_APPLET_JS_CODE2SESSION = '/sns/jscode2session'; // 小程序登录

    const GET_APPLET_USER_OPENID = '/wxa/getpluginopenpid'; // 获取用户openid

    public function __construct()
    {
        $this->_init();
    }

    /**
     * @return void
     */
    private function _init()
    {
        self::$domain = config('wechat.domain');
        self::$appId = config('wechat.appId');
        self::$appSecret = config('wechat.appSecret');
        self::$appPayId = config('wechat.appId');
        self::$mchId = config('wechat.mchId');
        self::$serial = config('wechat.serial');
        self::$mchSecretKey = config('wechat.mchSecretKey');
//        self::$certPem = config('wechat.certPemPath');
        self::$apiClientKeyPem = config('wechat.apiClientKeyPemPath');
        self::$apiClientCertPem = config('wechat.apiClientCertPemPath');
        self::$notifyPath = config('wechat.notifyPath');
    }

    /**
     * @return BuilderChainable
     */
    protected function getInstance(): BuilderChainable
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . self::$apiClientKeyPem;
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);

        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://' . self::$certPem;
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 从「微信支付平台证书」中获取「证书序列号」
//        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
        $platformCertificateSerial = 'PUB_KEY_ID_0117057767792025020500337100001502';

        // 构造一个 APIv3 客户端实例
        return Builder::factory([
            'mchid' => self::$mchId, // 商户号
            'serial' => self::$serial, // 「商户API证书」的「证书序列号」
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
    }

    /**
     * @param $prepayId
     * @return array
     */
    protected function getAppPayParams($prepayId): array
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . self::$apiClientKeyPem;

        $params = [
            'appid' => self::$appId,
            'timestamp' => Formatter::timestamp(),
            'noncestr' => Formatter::nonce(),
            'prepayid' => $prepayId,
        ];

        $params['sign'] = Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $merchantPrivateKeyFilePath,
        );

        $params['partnerid'] = self::$mchId;
        $params['package'] = 'Sign=WXPay';

        LogHelper::info('payment', ['appPayParams' => $params]);
        return $params;
    }

    /**
     * 设置额外参数
     *
     * @return void
     */
    protected function setBatchOptional(&$requestData, $batchOptional)
    {
        if (!empty($batchOptional['timeExpire'])) {
            $requestData['time_expire'] = timestampToRFC($batchOptional['timeExpire']);
        }
        $attach = [];
        if (!empty($batchOptional['params'])) {
            $attach = $batchOptional['params'];
        }

        if (!empty($attach)) {
            $requestData['attach'] = json_encode($attach);
        }
    }

    /**
     * 获取域名
     *
     * @return string
     */
    protected function getDomain(): string
    {
        return self::$domain;
    }
}
